using System;
using Gtk;
using doan_rss_02;
using System.Collections;
using Mono.WebBrowser;
using Mono.Data.Sqlite;
using nwind;
using System.Linq;

public partial class MainWindow: Gtk.Window
{	
	public MainWindow (): base (Gtk.WindowType.Toplevel)
	{
		Build ();

		sub_store = new Gtk.ListStore (typeof(Subscription));
		ite_store = new Gtk.ListStore (typeof(nwind.Item));
		var conn = new SqliteConnection (
			"DbLinqProvider=Sqlite;" +
			"Data Source=db_rss.db3"
		);

		db = new nwind.Main (conn);
		max_items = 100;
		Gtk.TreeViewColumn ar_state_col = new Gtk.TreeViewColumn ();
		ar_state_col.Title = "State";
		Gtk.CellRendererPixbuf ar_state_cell = new Gtk.CellRendererPixbuf ();
		ar_state_col.PackStart (ar_state_cell, true);
		ar_state_col.SetCellDataFunc (ar_state_cell, new Gtk.TreeCellDataFunc (RenderArticleState));

		/* Second column of trv_article_list */
		Gtk.TreeViewColumn ar_pubdate_col = new Gtk.TreeViewColumn ();
		ar_pubdate_col.Title = "PubDate";
		Gtk.CellRendererText ar_pubdate_cell = new Gtk.CellRendererText ();
		ar_pubdate_col.PackStart (ar_pubdate_cell, true);
		ar_pubdate_col.SetCellDataFunc (ar_pubdate_cell, new Gtk.TreeCellDataFunc (RenderArticlePubdate));

		/* Third column of trv_article_list */
		Gtk.TreeViewColumn ar_name_col = new Gtk.TreeViewColumn ();
		ar_name_col.Title = "Headline";
		Gtk.CellRendererText ar_name_cell = new Gtk.CellRendererText ();
		ar_name_col.PackStart (ar_name_cell, true);
		ar_name_col.SetCellDataFunc (ar_name_cell, new Gtk.TreeCellDataFunc (RenderArticleName));


		/* only column for trv_sub_node */
		Gtk.TreeViewColumn sub_name_col = new Gtk.TreeViewColumn ();
		sub_name_col.Title = "Subscription Name";
		Gtk.CellRendererText sub_name_cell = new Gtk.CellRendererText ();
		sub_name_col.PackStart (sub_name_cell, true);
		sub_name_col.SetCellDataFunc (sub_name_cell, new Gtk.TreeCellDataFunc (RenderSubscriptionName));

		trv_sub_node.Model = sub_store;
		trv_sub_node.AppendColumn (sub_name_col);
		trv_sub_node.CursorChanged += OnSubNameChanged;

		trv_article_list.Model = ite_store;
		trv_article_list.AppendColumn (ar_state_col);
		trv_article_list.AppendColumn (ar_pubdate_col);
		trv_article_list.AppendColumn (ar_name_col);
		trv_article_list.CursorChanged += OnArNameChanged;


		tv_article_content.WrapMode = WrapMode.Word;

		//Mono.WebBrowser.IWebBrowser browser = new Mono.WebBrowser.Manager.GetNewInstance(Mono.WebBrowser.Platform.Gtk);
	}

	public Folder sub_fol;
	public Folder uncategorized;
	Gtk.ListStore sub_store;
	Gtk.ListStore ite_store;
	public nwind.Main db;
	public int max_items; /* Maximum number alow to cached each subscription */
	public bool new_subscription; /* It is a new subscription */
	public int new_item_score;

	private void OnSearch (object obj, EventArgs args)
	{
		ite_store.Clear ();
		var all_items = from i in db.Item
			select i;
		foreach (nwind.Item i in all_items)
		{
			if (i.Headline.IndexOf(e_search.Text, StringComparison.CurrentCultureIgnoreCase) != -1)
			{
				add_item_node(i);
			}
			else if (i.Description.IndexOf(e_search.Text, StringComparison.CurrentCultureIgnoreCase) != -1)
			{
				add_item_node (i);
			}
		}
	}
	private void add_item_node (nwind.Item ite)
	{
		ite_store.AppendValues (ite);
	}
	private void OnSubNameChanged (object obj, EventArgs args)
	{
		Gtk.TreeModel model = sub_store;
		Gtk.TreeIter iter;
		trv_sub_node.Selection.GetSelected (out model, out iter);
		Subscription sub = (Subscription)model.GetValue (iter, 0);
		ite_store.Clear ();
		add_item_nodes (sub.SubscriptionUrl);
		Console.WriteLine ("Highest score is: " + highest_score(sub));
	}
	private void OnLoadDatabase (object obj, EventArgs args)
	{
		var subscriptions = from s in db.Subscription
			select s;
		foreach (Subscription s in subscriptions)
		{
			add_subscription_node (s.SubscriptionUrl);
		}
	}
	private void OnArNameChanged (object obj, EventArgs args)
	{
		Gtk.TreeModel model = ite_store;
		Gtk.TreeIter iter;
		trv_article_list.Selection.GetSelected (out model, out iter);
		nwind.Item ite = (nwind.Item)model.GetValue (iter, 0);
		tv_article_content.Buffer.Text = ite.Description;
		ite.Readed = "true";
		mark_readed (ite);
	}
	protected void OnDelete (object sender, EventArgs e)
	{
		Gtk.TreeModel model = sub_store;
		Gtk.TreeIter iter;
		trv_sub_node.Selection.GetSelected (out model, out iter);
		Subscription sub = (Subscription)model.GetValue (iter, 0);
		delete_items (sub);
		delete_subscription (sub);
		sub_store.Remove (ref iter);
	}
	protected void OnUpdateAll (object sender, EventArgs e)
	{
		int col = 0;
		Subscription current;
		foreach (object[] row in sub_store) {
			current = (Subscription)row [col];
			refresh_subscription (current);
		}
	}
	public int refresh_subscription(Subscription sub)
	{
		if (is_full (sub))
			reduce_subscription (sub);
		RssReader reader = new RssReader ();
		reader.RdfMode = false;
		RssFeed feed = reader.Retrieve (sub.SubscriptionUrl);
		push_items(feed.Items, sub);
		if (is_full (sub))
			reduce_subscription (sub);
		return 0;
	}
	private void RenderSubscriptionName (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
	{
		Subscription sub = (Subscription)model.GetValue (iter, 0);

		if (count_unread(sub) > 0) {
			(cell as Gtk.CellRendererText).Foreground = "violet";
		} else {
			(cell as Gtk.CellRendererText).Foreground = "black";
		}

		(cell as Gtk.CellRendererText).Text = sub.SubscriptionName + " (" + count_unread(sub) + ")";
	}
	private void RenderArticleState (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
	{
		nwind.Item ite = (nwind.Item)model.GetValue (iter, 0);

		if (ite.Readed == "true") {
			(cell as Gtk.CellRendererPixbuf).Pixbuf = new Gdk.Pixbuf ("old.png");
		} else {
			(cell as Gtk.CellRendererPixbuf).Pixbuf = new Gdk.Pixbuf ("new.png");
		}

	}
	private void RenderArticlePubdate (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
	{
		nwind.Item ite = (nwind.Item)model.GetValue (iter, 0);

		if (ite.Readed == "true") {
			(cell as Gtk.CellRendererText).Foreground = "black";
		} else {
			(cell as Gtk.CellRendererText).Foreground = "violet";
		}

		(cell as Gtk.CellRendererText).Text = ite.Pubdate;
	}
	private void RenderArticleName (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
	{
		nwind.Item ite = (nwind.Item)model.GetValue (iter, 0);

		if (ite.Readed == "true") {
			(cell as Gtk.CellRendererText).Foreground = "black";
		} else {
			(cell as Gtk.CellRendererText).Foreground = "violet";
		}

		(cell as Gtk.CellRendererText).Text = ite.Headline;
	}
	protected void OnDeleteEvent (object sender, DeleteEventArgs a)
	{
		Application.Quit ();
		a.RetVal = true;
	}
	protected void OnNewSubscription (object sender, EventArgs e)
	{
		; /* this is wrong the f** stetic generate code require this */
	}
	protected void OnNew (object sender, EventArgs e)
	{
		if (push_subscription (e_new_sub.Text) != 0)
			return;
		if (add_subscription_node (e_new_sub.Text) == 0)
			add_item_nodes (e_new_sub.Text);
		return;
	}
	public int add_item_nodes (String sub_url)
	{
		int this_id = get_subscription_id (sub_url);
		var item_found = from i in db.Item
			where i.Subscription == this_id
				select i;
		foreach (nwind.Item i in item_found)
		{
			ite_store.AppendValues(i);
		}
		return 0;
	}
	public int add_subscription_node(String sub_url)
	{
		var subscription_found = from s in db.Subscription
			where s.SubscriptionUrl == sub_url
				select s;
		foreach (Subscription s in subscription_found)
		{
			sub_store.AppendValues(s);
		}
		return 0;
	}
	public int push_subscription(String sub_url)
	{
		RssReader reader = new RssReader ();
		reader.RdfMode = false;
		// reader.ItemAdded += new EventHandler (reader_ItemAdded);
		if (is_pushed_subscription (sub_url))
			return 2; /* TODO: error code */
		RssFeed feed = reader.Retrieve (sub_url);
		
		nwind.Subscription sub_a = new nwind.Subscription ();

		sub_a.SubscriptionName = feed.Title;
		sub_a.SubscriptionUrl = sub_url;

		db.Subscription.InsertOnSubmit (sub_a);
		db.SubmitChanges ();

		sub_a.SubscriptionID = get_subscription_id (sub_a.SubscriptionUrl);

		if (sub_a.SubscriptionID == -1)
			return 3; /* TODO: error code, */

		new_subscription = true;
		new_item_score = 0;
		push_items (feed.Items, sub_a);

		return 0;
	}
	public int get_subscription_id(string sub_url)
	{
		var sub_found = from s in db.Subscription
			where s.SubscriptionUrl == sub_url
				select s;
		foreach (Subscription s in sub_found) {
			return Int32.Parse(s.SubscriptionID.ToString());
		}
		return -1; /* TODO: error code */
	}
	public int push_items(RssItems items, Subscription itsub)
	{
		nwind.Item temp;
		foreach (RssItem item in items) {
			temp = new nwind.Item();
			temp.Description = item.Description;
			temp.Author = item.Author;
			temp.Pubdate = item.Pubdate;
			temp.Headline = item.Title;
			temp.Readed = "false";
			temp.Score = new_subscription ? new_item_score++ : highest_score(itsub) + 1;
			temp.Guid = item.Link;
			temp.Subscription = itsub.SubscriptionID;
			if (is_pushed_item (temp))
			{
				continue; /* TODO: error code */
			}
			else
			{
				db.Item.InsertOnSubmit(temp);
			}
		}
		new_subscription = false;
		new_item_score = 0;
		db.SubmitChanges ();
		return 0;
	}
	public int count_unread (Subscription sub)
	{
		return db.Item.Count (r => r.Subscription == sub.SubscriptionID && r.Readed == "false");
	}
	public int count_all (Subscription sub)
	{
		return db.Item.Count (r => r.Subscription == sub.SubscriptionID);
	}
	public bool is_pushed_item(nwind.Item item)
	{
		return db.Item.Any (r => r.Guid == item.Guid);
	}
	public bool is_pushed_subscription(string sub_url)
	{
		return db.Subscription.Any (r => r.SubscriptionUrl == sub_url);
	}
	public bool is_full (Subscription sub)
	{
		return count_all(sub) > max_items ? true : false;
	}
	protected void OnQuit (object sender, EventArgs e)
	{
		db.SubmitChanges ();
		Application.Quit ();
	}
	protected void delete_subscription (Subscription  sub)
	{
		var sub_found = from s in db.Subscription
			where s.SubscriptionID == sub.SubscriptionID
				select s;

		db.Subscription.DeleteAllOnSubmit (sub_found);
		db.SubmitChanges ();
	}
	protected void delete_items(Subscription sub)
	{
		var items = from i in db.Item
			where i.Subscription == sub.SubscriptionID
				select i;
		db.Item.DeleteAllOnSubmit(items);
		db.SubmitChanges ();
	}
	protected void mark_readed(nwind.Item ite)
	{
		var item_found = from i in db.Item
			where i.Guid == ite.Guid
				select i;
		foreach (nwind.Item i in item_found) {
			i.Readed = "true";
		}
		db.SubmitChanges ();
	}
	protected int decrease_score (Subscription sub)
	{
		var items_of_sub = from i in db.Item
			where i.Subscription == sub.SubscriptionID
				select i;

		foreach (nwind.Item i in items_of_sub) {
			i.Score = i.Score - 1;
		}
		db.SubmitChanges ();
		return 0;
	}
	public int highest_score (Subscription sub)
	{
		var score = from i in db.Item
			where i.Subscription == sub.SubscriptionID
				select i.Score;
		return Int32.Parse (score.Max ().ToString ());
	}
	public int lowest_score (Subscription sub)
	{
		var score = from i in db.Item
			where i.Subscription == sub.SubscriptionID
				select i.Score;
		return Int32.Parse(score.Min ().ToString ());
	}
	public int kill_oldest_item(Subscription sub)
	{
		var item = from i in db.Item
			where i.Subscription == sub.SubscriptionID && i.Score == lowest_score(sub)
				select i;
		db.Item.DeleteAllOnSubmit(item);
		db.SubmitChanges ();
		return 0;
	}
	public int reduce_subscription (Subscription sub)
	{
		while (is_full(sub))
			kill_oldest_item (sub);
		decrease_score (sub);
		return 0;
	}
}
